package com.zhoug.bluetooth;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.ParcelUuid;

import androidx.annotation.NonNull;


import com.zhoug.logging.Logger;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Objects;
import java.util.UUID;

/**
 * 打印工具
 *
 * @Author: zhoug
 * @Date: 2024-06-26
 * @Description:
 */
@SuppressLint("MissingPermission")
public class PrintHelper {
    private static final String TAG = ">>>zbluetooth";
    /**
     * 编码
     */
    private String charset = "gb2312";
    /**
     * 打印纸一行最大的字节
     */
    private int lineByteSize = 48;


    //    private static final String UUID_DEF = "00001005-0000-1000-8000-00805F9B34FB";
    private static final String UUID_DEF = "00001101-0000-1000-8000-00805f9b34fb";
    private final BluetoothDevice mDevice;
    private BluetoothSocket mSocket;

    private String mUUID;

    public void setUuid(String uuid) {
        this.mUUID = uuid;
    }

    public PrintHelper(@NonNull BluetoothDevice device) {
        this.mDevice = device;
    }

    /**
     * 判断给定的设备和当前设备是否是同一个设备
     *
     * @param device 给定的设备
     * @return 是否是同一个设备
     */
    public boolean isSameDevice(@NonNull BluetoothDevice device) {
        return Objects.equals(mDevice.getAddress(), device.getAddress());
    }

    /**
     * 初始化 socket
     *
     * @throws Exception
     */
    private void initSocket() throws Exception {
        UUID uuid = null;
        if (mUUID == null) {
            ParcelUuid[] uuids = mDevice.getUuids();
            if (uuids != null && uuids.length > 0) {
                for (ParcelUuid item : uuids) {
                    if (item != null && item.getUuid() != null) {
                        if (!Objects.equals("00000000-0000-0000-0000-000000000000", item.getUuid().toString())) {
                            uuid = item.getUuid();
                            break;
                        }
                    }
                }
            }
            if (uuid == null) {
                uuid = UUID.fromString(UUID_DEF);
            }
        } else {
            uuid = UUID.fromString(mUUID);
        }

        try {
            Logger.d(TAG, "创建Socket uuid=" + uuid);
            mSocket = mDevice.createRfcommSocketToServiceRecord(uuid);
        } catch (IOException e) {
            Logger.e(TAG, "创建Socket失败" + e.getMessage());
            throw new Exception("创建Socket失败");
        }

    }

    /**
     * 连接
     */
    public void connect() throws Exception {
        if (mSocket == null) {
            initSocket();
        }
        if (mSocket == null) return;
        // Cancel discovery because it otherwise slows down the connection.
        BluetoothAdapter defaultAdapter = BluetoothAdapter.getDefaultAdapter();
        if (defaultAdapter != null && defaultAdapter.isDiscovering()) {
            defaultAdapter.cancelDiscovery();
        }
        try {
            Logger.d(TAG, "Socket 连接中... ");
            mSocket.connect();
        } catch (IOException e) {
            Logger.e(TAG, "Socket连接失败 " + e.getMessage());
            throw new Exception("Socket连接失败");
        }
    }

    /**
     * 是否连接
     *
     * @return
     */
    public boolean isConnected() {
        return mSocket != null && mSocket.isConnected();
    }

    /**
     * 关闭连接
     */
    public void close() {
        try {
            if (isConnected()) {
                Logger.d(TAG, "关闭socket连接");
                mSocket.close();
                mSocket = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
            Logger.e(TAG, "关闭socket连接失败" + e.getMessage());
        }
    }

    /**
     * 设置编码
     *
     * @param charset 编码 默认 gb2312
     */
    public void setCharset(String charset) {
        if (charset != null) {
            this.charset = charset;
        }
    }

    /**
     * 设置打印纸一行最大的字节
     *
     * @param lineByteSize 打印纸一行最大的字节
     */
    public void setLineByteSize(int lineByteSize) {
        if (lineByteSize > 0) {
            this.lineByteSize = lineByteSize;
        }
    }

    /**
     * 设置打印格式
     *
     * @param command 格式指令{@link ESC}
     */
    public void setCommand(byte[] command) throws IOException {
        if (command == null || command.length == 0) return;
        OutputStream outputStream = mSocket.getOutputStream();
        outputStream.write(command);
        outputStream.flush();
    }

    /**
     * 打印文字
     *
     * @param text 要打印的文字
     */
    public void printText(String text) throws IOException {
        if (text == null) return;
        byte[] data = text.getBytes(charset);
//        Logger.d(TAG, "printText length:" + data.length);
        OutputStream outputStream = mSocket.getOutputStream();
        outputStream.write(data, 0, data.length);
        outputStream.flush();
    }

    /**
     * 打印字节数组
     *
     * @param data 要打印的字节数组
     */
    public void printBytes(byte[] data) throws IOException {
        if (data == null || data.length == 0) return;
        OutputStream outputStream = mSocket.getOutputStream();
        outputStream.write(data, 0, data.length);
        outputStream.flush();
    }

    public void printLine(int line) throws IOException {
        OutputStream outputStream = mSocket.getOutputStream();
        byte[] data = "\n".getBytes(charset);
        for (int i = 0; i < line; i++) {
            outputStream.write(data, 0, data.length);
        }
        outputStream.flush();
    }

    public void printLine() throws IOException {
        OutputStream outputStream = mSocket.getOutputStream();
        byte[] data = "\n".getBytes(charset);
        outputStream.write(data, 0, data.length);
        outputStream.flush();
    }

    public void printDashedLine() throws IOException {
        OutputStream outputStream = mSocket.getOutputStream();
        byte[] data = "-".getBytes(charset);
        for (int i = 0; i < lineByteSize; i++) {
            outputStream.write(data, 0, data.length);
        }
        outputStream.flush();
    }

    public void printDivisionLine() throws IOException {
        OutputStream outputStream = mSocket.getOutputStream();
        byte[] data = "-".getBytes(charset);
        for (int i = 0; i < lineByteSize; i++) {
            outputStream.write(data, 0, data.length);
        }
        outputStream.flush();
    }

    /**
     * 打印两列
     *
     * @param leftText  左侧文字
     * @param rightText 右侧文字
     * @return
     */
    public void printKeyValue(String leftText, String rightText) throws IOException {
        if (leftText == null && rightText == null) return;
        if (leftText == null) {
            leftText = "";
        }
        if (rightText == null) {
            rightText = "";
        }
        String result = leftText;
        String temp = leftText;
        int leftLength = leftText.getBytes(charset).length;
        int line = 1;
        for (int i = 0; i < rightText.length(); i++) {
            char c = rightText.charAt(i);
            temp = temp + c;
            if (temp.getBytes(charset).length >= line * lineByteSize) {
                temp = result;
                while (temp.getBytes(charset).length < leftLength + line * lineByteSize) {
                    temp = temp + " ";
                }
                line++;
            }
            result = temp;

        }
        printText(result);
    }

    /**
     * 打印文字,右对齐
     *
     * @param text
     * @throws IOException
     */
    public void printAlignRight(int leftMargin, String text) throws IOException {
        if (text == null) return;
        while ((text.getBytes(charset).length + leftMargin) < lineByteSize) {
            text = " " + text;
        }
        printText(text);
    }


    public void printTable(String... tables) throws IOException {
        if (tables != null && tables.length > 0) {
            int length = tables.length;
            int tableWidth = lineByteSize / 4;
            String result = "";
            for (int i = 0; i < tables.length; i++) {
                String item = tables[i];
                if (item == null) {
                    item = "";
                }
                result = result + item;
                while (result.getBytes(charset).length < tableWidth * (i + 1)) {
                    result = result + " ";
                }

            }
            printText(result);
        }

    }


    /**
     * 打印图片
     *
     * @param bitmap 图片
     * @throws IOException 异常
     */
    public void printBitmap(Bitmap bitmap, int paperwidth) throws IOException {
        if (bitmap == null) return;
        Bitmap resizeBitmap = compressPic(bitmap, paperwidth);
        byte[] bmpByteArray = draw2PxPoint(resizeBitmap);
        printBytes(bmpByteArray);

    }


    /*************************************************************************
     * 假设一个360*360的图片，分辨率设为24, 共分15行打印 每一行,是一个 360 * 24 的点阵,y轴有24个点,存储在3个byte里面。
     * 即每个byte存储8个像素点信息。因为只有黑白两色，所以对应为1的位是黑色，对应为0的位是白色
     **************************************************************************/
    private byte[] draw2PxPoint(Bitmap bmp) {
        //计算所需字节空间大小
        int bitmapsize = (int) (Math.ceil(bmp.getHeight() / 24f)) * bmp.getWidth() * 3;
        int cmdsize = (int) (Math.ceil(bmp.getHeight() / 24f)) * 6 + 5;
        int size = bitmapsize + cmdsize;
        byte[] tmp = new byte[size];
        int k = 0;
        // 设置行距为0
        tmp[k++] = 0x1B;
        tmp[k++] = 0x33;
        tmp[k++] = 0x00;
        for (int j = 0; j < bmp.getHeight() / 24f; j++) {
            tmp[k++] = 0x1B;
            tmp[k++] = 0x2A;// 0x1B 2A 表示图片打印指令
            tmp[k++] = 33; // m=33时，选择24点密度打印
            tmp[k++] = (byte) (bmp.getWidth() % 256); // nL
            tmp[k++] = (byte) (bmp.getWidth() / 256); // nH
            for (int i = 0; i < bmp.getWidth(); i++) {
                for (int m = 0; m < 3; m++) {
                    for (int n = 0; n < 8; n++) {
                        byte b = px2Byte(i, j * 24 + m * 8 + n, bmp);
                        tmp[k] += tmp[k] + b;
                    }
                    k++;
                }
            }
            tmp[k++] = 10;// 换行
        }
        // 恢复默认行距
        tmp[k++] = 0x1B;
        tmp[k++] = 0x32;

        byte[] result = new byte[k];
        System.arraycopy(tmp, 0, result, 0, k);
        return result;
    }

    /**
     * 图片二值化，黑色是1，白色是0
     *
     * @param x   横坐标
     * @param y   纵坐标
     * @param bit 位图
     * @return
     */
    private byte px2Byte(int x, int y, Bitmap bit) {
        if (x < bit.getWidth() && y < bit.getHeight()) {
            byte b;
            int pixel = bit.getPixel(x, y);
            int red = (pixel & 0x00ff0000) >> 16; // 取高两位
            int green = (pixel & 0x0000ff00) >> 8; // 取中两位
            int blue = pixel & 0x000000ff; // 取低两位
            int gray = RGB2Gray(red, green, blue);
            if (gray < 128) {
                b = 1;
            } else {
                b = 0;
            }
            return b;
        }
        return 0;
    }

    /**
     * 图片灰度的转化
     */
    private int RGB2Gray(int r, int g, int b) {
        int gray = (int) (0.29900 * r + 0.58700 * g + 0.11400 * b); // 灰度转化公式
        return gray;
    }


    public byte[] getGbkStr(String stText) {
        byte[] returnText = null;
        try {
            returnText = stText.getBytes("GBK");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return returnText;
    }


    /**
     * 图片压缩
     *
     * @param bitmap     图片
     * @param paperwidth 纸张宽度
     * @return
     */
    public static Bitmap compressPic(Bitmap bitmap, int paperwidth) {
        // 获取这个图片的宽和高
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();

        int newWidth = paperwidth;
        int newHeight = Math.round(height * newWidth / width);
        Bitmap targetBmp = Bitmap.createBitmap(newWidth, newHeight,
                Bitmap.Config.ARGB_8888);
        Canvas targetCanvas = new Canvas(targetBmp);
        targetCanvas.drawColor(0xffffffff);
        targetCanvas.drawBitmap(bitmap, new Rect(0, 0, width, height),
                new Rect(0, 0, newWidth, newHeight), null);

        return targetBmp;
    }


    /**
     * 获取数据长度
     *
     * @param msg
     * @return
     */
    public int getBytesLength(String msg) {
        try {
            if (msg != null) {
                return msg.getBytes(charset).length;
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return 0;


    }
}
